home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / net / RCS / res_send.c,v < prev    next >
Text File  |  1988-07-29  |  9KB  |  433 lines

  1. head     1.3;
  2. access   ;
  3. symbols  ;
  4. locks    ; strict;
  5. comment  @ * @;
  6.  
  7.  
  8. 1.3
  9. date     88.07.29.17.00.02;  author ouster;  state Exp;
  10. branches ;
  11. next     1.2;
  12.  
  13. 1.2
  14. date     88.07.25.13.45.13;  author ouster;  state Exp;
  15. branches ;
  16. next     1.1;
  17.  
  18. 1.1
  19. date     88.06.20.09.57.21;  author ouster;  state Exp;
  20. branches ;
  21. next     ;
  22.  
  23.  
  24. desc
  25. @@
  26.  
  27.  
  28. 1.3
  29. log
  30. @Lint.
  31. @
  32. text
  33. @/*
  34.  * Copyright (c) 1985 Regents of the University of California.
  35.  * All rights reserved.
  36.  *
  37.  * Redistribution and use in source and binary forms are permitted
  38.  * provided that this notice is preserved and that due credit is given
  39.  * to the University of California at Berkeley. The name of the University
  40.  * may not be used to endorse or promote products derived from this
  41.  * software without specific prior written permission. This software
  42.  * is provided ``as is'' without express or implied warranty.
  43.  */
  44.  
  45. #if defined(LIBC_SCCS) && !defined(lint)
  46. static char sccsid[] = "@@(#)res_send.c    6.20 (Berkeley) 5/19/88";
  47. #endif /* LIBC_SCCS and not lint */
  48.  
  49. /*
  50.  * Send query to name server and wait for reply.
  51.  */
  52.  
  53. #include <sys/param.h>
  54. #include <sys/time.h>
  55. #include <sys/socket.h>
  56. #include <sys/uio.h>
  57. #include <netinet/in.h>
  58. #include <stdio.h>
  59. #include <errno.h>
  60. #include <arpa/nameser.h>
  61. #include <resolv.h>
  62.  
  63. extern int errno;
  64.  
  65. static int s = -1;    /* socket used for communications */
  66. static struct sockaddr no_addr;
  67.   
  68.  
  69. #ifndef FD_SET
  70. #define    NFDBITS        32
  71. #define    FD_SETSIZE    32
  72. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  73. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  74. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  75. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  76. #endif
  77.  
  78. #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
  79. #define BSD 43
  80.  
  81. res_send(buf, buflen, answer, anslen)
  82.     char *buf;
  83.     int buflen;
  84.     char *answer;
  85.     int anslen;
  86. {
  87.     register int n;
  88.     int retry, v_circuit, resplen, ns;
  89.     int gotsomewhere = 0, connected = 0;
  90.     u_short id, len;
  91.     char *cp;
  92.     fd_set dsmask;
  93.     struct timeval timeout;
  94.     HEADER *hp = (HEADER *) buf;
  95.     HEADER *anhp = (HEADER *) answer;
  96.     struct iovec iov[2];
  97.     int terrno = ETIMEDOUT;
  98.     char junk[512];
  99.  
  100. #ifdef DEBUG
  101.     if (_res.options & RES_DEBUG) {
  102.         printf("res_send()\n");
  103.         p_query(buf);
  104.     }
  105. #endif DEBUG
  106.     if (!(_res.options & RES_INIT))
  107.         if (res_init() == -1) {
  108.             return(-1);
  109.         }
  110.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  111.     id = hp->id;
  112.     /*
  113.      * Send request, RETRY times, or until successful
  114.      */
  115.     for (retry = _res.retry; retry > 0; retry--) {
  116.        for (ns = 0; ns < _res.nscount; ns++) {
  117. #ifdef DEBUG
  118.         if (_res.options & RES_DEBUG)
  119.             printf("Querying server (# %d) address = %s\n", ns+1,
  120.                   inet_ntoa(_res.nsaddr_list[ns].sin_addr));
  121. #endif DEBUG
  122.         if (v_circuit) {
  123.             int truncated = 0;
  124.  
  125.             /*
  126.              * Use virtual circuit.
  127.              */
  128.             if (s < 0) {
  129.                 s = socket(AF_INET, SOCK_STREAM, 0);
  130.                 if (s < 0) {
  131.                     terrno = errno;
  132. #ifdef DEBUG
  133.                     if (_res.options & RES_DEBUG)
  134.                         perror("socket failed");
  135. #endif DEBUG
  136.                     continue;
  137.                 }
  138.                 if (connect(s,
  139.                     (struct sockaddr *) &(_res.nsaddr_list[ns]),
  140.                     sizeof(struct sockaddr)) < 0) {
  141.                     terrno = errno;
  142. #ifdef DEBUG
  143.                     if (_res.options & RES_DEBUG)
  144.                         perror("connect failed");
  145. #endif DEBUG
  146.                     (void) close(s);
  147.                     s = -1;
  148.                     continue;
  149.                 }
  150.             }
  151.             /*
  152.              * Send length & message
  153.              */
  154.             len = htons((u_short)buflen);
  155.             iov[0].iov_base = (caddr_t)&len;
  156.             iov[0].iov_len = sizeof(len);
  157.             iov[1].iov_base = buf;
  158.             iov[1].iov_len = buflen;
  159.             if (writev(s, iov, 2) != sizeof(len) + buflen) {
  160.                 terrno = errno;
  161. #ifdef DEBUG
  162.                 if (_res.options & RES_DEBUG)
  163.                     perror("write failed");
  164. #endif DEBUG
  165.                 (void) close(s);
  166.                 s = -1;
  167.                 continue;
  168.             }
  169.             /*
  170.              * Receive length & response
  171.              */
  172.             cp = answer;
  173.             len = sizeof(short);
  174.             while (len != 0 &&
  175.                 (n = read(s, (char *)cp, (int)len)) > 0) {
  176.                 cp += n;
  177.                 len -= n;
  178.             }
  179.             if (n <= 0) {
  180.                 terrno = errno;
  181. #ifdef DEBUG
  182.                 if (_res.options & RES_DEBUG)
  183.                     perror("read failed");
  184. #endif DEBUG
  185.                 (void) close(s);
  186.                 s = -1;
  187.                 continue;
  188.             }
  189.             cp = answer;
  190.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  191. #ifdef DEBUG
  192.                 if (_res.options & RES_DEBUG)
  193.                     fprintf(stderr, "response truncated\n");
  194. #endif DEBUG
  195.                 len = anslen;
  196.                 truncated = 1;
  197.             } else
  198.                 len = resplen;
  199.             while (len != 0 &&
  200.                (n = read(s, (char *)cp, (int)len)) > 0) {
  201.                 cp += n;
  202.                 len -= n;
  203.             }
  204.             if (n <= 0) {
  205.                 terrno = errno;
  206. #ifdef DEBUG
  207.                 if (_res.options & RES_DEBUG)
  208.                     perror("read failed");
  209. #endif DEBUG
  210.                 (void) close(s);
  211.                 s = -1;
  212.                 continue;
  213.             }
  214.             if (truncated) {
  215.                 /*
  216.                  * Flush rest of answer
  217.                  * so connection stays in synch.
  218.                  */
  219.                 anhp->tc = 1;
  220.                 len = resplen - anslen;
  221.                 while (len != 0) {
  222.                     n = (len > sizeof(junk) ?
  223.                         sizeof(junk) : len);
  224.                     if ((n = read(s, junk, n)) > 0)
  225.                         len -= n;
  226.                     else
  227.                         break;
  228.                 }
  229.             }
  230.         } else {
  231.             /*
  232.              * Use datagrams.
  233.              */
  234.             if (s < 0)
  235.                 s = socket(AF_INET, SOCK_DGRAM, 0);
  236. #if    BSD >= 43
  237.             if (_res.nscount == 1 || retry == _res.retry) {
  238.                 /*
  239.                  * Don't use connect if we might
  240.                  * still receive a response
  241.                  * from another server.
  242.                  */
  243.                 if (connected == 0) {
  244.                     if (connect(s, (struct sockaddr *) &_res.nsaddr_list[ns],
  245.                         sizeof(struct sockaddr)) < 0) {
  246. #ifdef DEBUG
  247.                         if (_res.options & RES_DEBUG)
  248.                             perror("connect");
  249. #endif DEBUG
  250.                         continue;
  251.                     }
  252.                     connected = 1;
  253.                 }
  254.                 if (send(s, buf, buflen, 0) != buflen) {
  255. #ifdef DEBUG
  256.                     if (_res.options & RES_DEBUG)
  257.                         perror("send");
  258. #endif DEBUG
  259.                     continue;
  260.                 }
  261.             } else {
  262.                 /*
  263.                  * Disconnect if we want to listen
  264.                  * for responses from more than one server.
  265.                  */
  266.                 if (connected) {
  267.                     (void) connect(s, &no_addr,
  268.                         sizeof(no_addr));
  269.                     connected = 0;
  270.                 }
  271. #endif BSD
  272.                 if (sendto(s, buf, buflen, 0,
  273.                     (struct sockaddr *) &_res.nsaddr_list[ns],
  274.                     sizeof(struct sockaddr)) != buflen) {
  275. #ifdef DEBUG
  276.                     if (_res.options & RES_DEBUG)
  277.                         perror("sendto");
  278. #endif DEBUG
  279.                     continue;
  280.                 }
  281. #if    BSD >= 43
  282.             }
  283. #endif
  284.  
  285.             /*
  286.              * Wait for reply
  287.              */
  288.             timeout.tv_sec = (_res.retrans << (_res.retry - retry))
  289.                 / _res.nscount;
  290.             if (timeout.tv_sec <= 0)
  291.                 timeout.tv_sec = 1;
  292.             timeout.tv_usec = 0;
  293. wait:
  294.             FD_ZERO(&dsmask);
  295.             FD_SET(s, &dsmask);
  296.             n = select(s+1, (int *) &dsmask, (int *) NULL,
  297.                 (int *) NULL, &timeout);
  298.             if (n < 0) {
  299. #ifdef DEBUG
  300.                 if (_res.options & RES_DEBUG)
  301.                     perror("select");
  302. #endif DEBUG
  303.                 continue;
  304.             }
  305.             if (n == 0) {
  306.                 /*
  307.                  * timeout
  308.                  */
  309. #ifdef DEBUG
  310.                 if (_res.options & RES_DEBUG)
  311.                     printf("timeout\n");
  312. #endif DEBUG
  313.                 gotsomewhere = 1;
  314.                 continue;
  315.             }
  316.             if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
  317. #ifdef DEBUG
  318.                 if (_res.options & RES_DEBUG)
  319.                     perror("recvfrom");
  320. #endif DEBUG
  321.                 continue;
  322.             }
  323.             gotsomewhere = 1;
  324.             if (id != anhp->id) {
  325.                 /*
  326.                  * response from old query, ignore it
  327.                  */
  328. #ifdef DEBUG
  329.                 if (_res.options & RES_DEBUG) {
  330.                     printf("old answer:\n");
  331.                     p_query(answer);
  332.                 }
  333. #endif DEBUG
  334.                 goto wait;
  335.             }
  336.             if (!(_res.options & RES_IGNTC) && anhp->tc) {
  337.                 /*
  338.                  * get rest of answer
  339.                  */
  340. #ifdef DEBUG
  341.                 if (_res.options & RES_DEBUG)
  342.                     printf("truncated answer\n");
  343. #endif DEBUG
  344.                 (void) close(s);
  345.                 s = -1;
  346.                 /*
  347.                  * retry decremented on continue
  348.                  * to desired starting value
  349.                  */
  350.                 retry = _res.retry + 1;
  351.                 v_circuit = 1;
  352.                 continue;
  353.             }
  354.         }
  355. #ifdef DEBUG
  356.         if (_res.options & RES_DEBUG) {
  357.             printf("got answer:\n");
  358.             p_query(answer);
  359.         }
  360. #endif DEBUG
  361.         /*
  362.          * We are going to assume that the first server is preferred
  363.          * over the rest (i.e. it is on the local machine) and only
  364.          * keep that one open.
  365.          */
  366.         if ((_res.options & KEEPOPEN) == 0 || ns != 0) {
  367.             (void) close(s);
  368.             s = -1;
  369.         }
  370.         return (resplen);
  371.        }
  372.     }
  373.     if (s >= 0) {
  374.         (void) close(s);
  375.         s = -1;
  376.     }
  377.     if (v_circuit == 0)
  378.         if (gotsomewhere == 0)
  379.             errno = ECONNREFUSED;
  380.         else
  381.             errno = ETIMEDOUT;
  382.     else
  383.         errno = terrno;
  384.     return (-1);
  385. }
  386.  
  387. /*
  388.  * This routine is for closing the socket if a virtual circuit is used and
  389.  * the program wants to close it.  This provides support for endhostent()
  390.  * which expects to close the socket.
  391.  *
  392.  * This routine is not expected to be user visible.
  393.  */
  394. _res_close()
  395. {
  396.     if (s != -1) {
  397.         (void) close(s);
  398.         s = -1;
  399.     }
  400. }
  401. @
  402.  
  403.  
  404. 1.2
  405. log
  406. @Define BSD = 43.
  407. @
  408. text
  409. @d106 3
  410. a108 2
  411.                 if (connect(s, &(_res.nsaddr_list[ns]),
  412.                    sizeof(struct sockaddr)) < 0) {
  413. d212 1
  414. a212 1
  415.                     if (connect(s, &_res.nsaddr_list[ns],
  416. d241 1
  417. a241 1
  418.                     &_res.nsaddr_list[ns],
  419. d264 2
  420. a265 2
  421.             n = select(s+1, &dsmask, (fd_set *)NULL,
  422.                 (fd_set *)NULL, &timeout);
  423. @
  424.  
  425.  
  426. 1.1
  427. log
  428. @Initial revision
  429. @
  430. text
  431. @d47 1
  432. @
  433.